﻿import { RedDotType, TB } from '../../../Data/Types';
import { RedDotInfo } from './RedDotInfo';
import { RedDotUnitInfo } from './RedDotUnitInfo';
import { OpenFuncConfig } from '../../../Game/Config/OpenFuncConfig';
import { RedDotUtilities } from '../../../Game/Config/ReDotUtilities';
import { Singleton } from '../../Manager/BaseManager';
import { Trie } from '../PoolObj/Trie';
import { DataMgr } from '../../Manager/DataManager';

/** 红点数据单例类 */
export class RedDotModel extends Singleton {
  className: string = 'RedDotModel';
  /** 红点前缀树 */
  redDotTrie: Trie;

  /** 红点名和红点信息Map<红点名, 红点信息> */
  private redDotInfoMap: Map<string, RedDotInfo>;

  /** 红点名和红点信息Map<红点名, 影响红点的运算单元> */
  private redDotNameHaveUnitMap: Map<string, string[]>;

  /** 计算红点显示逻辑 信息Map<红点运算单元名, 红点运算单元信息> */
  private mRedDotUnitInfoMap: Map<string, RedDotUnitInfo>;

  /**
   * 构造函数
   * 初始化
   */
  constructor() {
    super();
    this.redDotInfoMap = new Map<string, RedDotInfo>();
    this.redDotNameHaveUnitMap = new Map<string, string[]>();
    this.redDotTrie = new Trie();
    this.mRedDotUnitInfoMap = new Map<string, RedDotUnitInfo>();
  }

  /**
   * 初始化红点
   */
  public initRedDotUnitInfo() {
    // this.addRedDotConfigArr(RedDotConfig.getdefaultRedDot());
    const tb = DataMgr.tables.TbGameFunction.getDataList();
    const redDotNames: TB.GameFunction[] = [];
    tb.forEach((func) => {
      if (!OpenFuncConfig.judgeOpenFunc(func.open)) return;
      redDotNames.push(func);
    });
    this.addRedDotConfig(redDotNames);
  }

  /**
   * 添加红点配置
   * @param redDotFunc - 红点功能
   * @returns 红点名称或名称列表
   */
  private addRedDotConfig(redDotFunc: TB.GameFunction): string;
  private addRedDotConfig(redDotFunc: TB.GameFunction[]): string[];
  private addRedDotConfig(redDotFunc: number): string;
  private addRedDotConfig(redDotFunc: number[]): string[];
  private addRedDotConfig(redDotFunc: TB.GameFunction | TB.GameFunction[] | number | number[]): string | string[] {
    //结果
    let result: string | string[];
    if (Array.isArray(redDotFunc)) {
      result = [];
      if (redDotFunc[0] instanceof TB.GameFunction) {
        (redDotFunc as TB.GameFunction[]).forEach((func: TB.GameFunction) => {
          this.initRedDot(func);
          (result as string[]).push(func.redDotName);
        });
      } else if (typeof redDotFunc[0] === 'number') {
        const tb = DataMgr.tables.TbGameFunction;
        (redDotFunc as number[]).forEach((funcId: number) => {
          const func = tb.get(funcId);
          this.initRedDot(func);
          (result as string[]).push(func.redDotName);
        });
      }
      return result as string[];
    } else {
      if (redDotFunc instanceof TB.GameFunction) {
        this.initRedDot(redDotFunc);
        result = redDotFunc.redDotName;
      } else if (typeof redDotFunc === 'number') {
        const tb = DataMgr.tables.TbGameFunction;
        const func = tb.get(redDotFunc);
        this.initRedDot(func);
        result = func.redDotName;
      }
      return result as string;
    }
  }

  /**
   * 初始化红点
   * @param func - 红点功能
   */
  private initRedDot(func: TB.GameFunction) {
    this.redDotTrie.addWord(func.redDotName);
    this.redDotNameHaveUnitMap.set(func.redDotName, func.redDotUnit);
    const tbu = DataMgr.tables.TbRedDotUnit;
    func.redDotUnit.forEach((unit: string) => {
      if (this.mRedDotUnitInfoMap.has(unit)) return;
      const unitInfo = tbu.get(unit);
      const f = RedDotUtilities.getUnitFunc(unit);
      this.addRedDotUnitInfo(unit, func.redDotName, unitInfo.type, f, unitInfo.param);
    });
  }

  /**
   * 添加红点信息
   * @param redDotName - 红点名称
   * @returns 红点信息
   */
  addRedDotInfo(redDotName: string): RedDotInfo {
    if (this.redDotInfoMap.has(redDotName)) {
      return this.redDotInfoMap.get(redDotName);
    }
    const redDotInfo = new RedDotInfo(redDotName);
    this.redDotInfoMap.set(redDotName, redDotInfo);
    return redDotInfo;
  }

  /**
   * 添加红点运算单元信息
   * @param redDotUnit - 红点运算单元
   * @param redDotName - 红点名称
   * @param redDotType - 红点类型
   * @param caculateFunc - 计算函数
   * @param param - 参数
   * @returns 红点运算单元信息
   */
  private addRedDotUnitInfo(redDotUnit: string, redDotName: string, redDotType: RedDotType = RedDotType.NUMBER, caculateFunc: () => number, param: string): RedDotUnitInfo {
    const redDotUnitInfo: RedDotUnitInfo = new RedDotUnitInfo(redDotUnit, redDotType, caculateFunc, param);
    redDotUnitInfo.addRedDotName(redDotName);
    this.mRedDotUnitInfoMap.set(redDotUnit, redDotUnitInfo);
    return redDotUnitInfo;
  }

  /**
   * 获取红点名和红点信息Map<红点名, 红点信息>
   * @returns 红点信息Map
   */
  getRedDotInfoMap(): Map<string, RedDotInfo> {
    return this.redDotInfoMap;
  }

  /**
   * 获取红点运算单元信息Map<红点运算单元门, 红点运算单元信息>
   * @returns 红点运算单元信息Map
   */
  getRedDotUnitInfoMap(): Map<string, RedDotUnitInfo> {
    return this.mRedDotUnitInfoMap;
  }

  /**
   * 获取指定红点名的红点信息
   * @param redDotName - 红点名称
   * @returns 红点信息
   */
  getRedDotInfoByName(redDotName: string): RedDotInfo {
    if (!this.redDotInfoMap.has(redDotName)) {
      // Debug.LogError($"找不到红点名:{redDotName}的红点信息!");
      return null;
    }
    return this.redDotInfoMap.get(redDotName);
  }

  /**
   * 获取指定红点运算单元的红点运算单元信息
   * @param redDotUnit - 红点运算单元
   * @returns 红点运算单元信息
   */
  getRedDotUnitInfo(redDotUnit: string): RedDotUnitInfo {
    if (!this.mRedDotUnitInfoMap.has(redDotUnit)) {
      //Debug.LogError($"找不到红点运算单元:{redDotUnit.ToString()}的信息!");
      return null;
    }
    return this.mRedDotUnitInfoMap.get(redDotUnit);
  }

  /**
   * 获取指定红点运算单元影响的红点名列表
   * @param redDotUnit - 红点运算单元
   * @returns 红点名列表
   */
  getRedDotUnitNames(redDotUnit: string): Array<string> {
    const redDotUnitInfo: RedDotUnitInfo = this.getRedDotUnitInfo(redDotUnit);
    return redDotUnitInfo?.redDotNameLsit;
  }

  /**
   * 获取指定红点运算单元的计算委托
   * @param redDotUnit - 红点运算单元
   * @returns 计算函数
   */
  getUnitCalculateFunc(redDotUnit: string): () => number {
    const redDotUnitInfo: RedDotUnitInfo = this.getRedDotUnitInfo(redDotUnit);
    return redDotUnitInfo?.calculateFunc;
  }

  /**
   * 获取指定红点运算单元的红点类型
   * @param redDotUnit - 红点运算单元
   * @returns 红点类型
   */
  getRedDotUnitRedType(redDotUnit: string): RedDotType {
    const redDotUnitInfo: RedDotUnitInfo = this.getRedDotUnitInfo(redDotUnit);
    if (redDotUnitInfo != null) {
      return redDotUnitInfo.redDotType;
    }
    // Debug.LogError($"获取红点运算单元:{redDotUnit}的红点类型失败!");
    return RedDotType.NONE;
  }

  /**
   * 获取指定红点名的所有红点运算单元列表
   * @param redDotName - 红点名称
   * @returns 红点运算单元列表
   */
  getRedDotUnitsByName(redDotName: string): Array<string> {
    if (!this.redDotNameHaveUnitMap.has(redDotName)) {
      //Debug.LogError($"找不到红点运算单元:{redDotUnit.ToString()}的信息!");
      return null;
    }
    return this.redDotNameHaveUnitMap.get(redDotName);
  }

  /**
   * 打开红点
   * @param redDotName - 红点名称或名称列表
   */
  openRedDot(redDotName: TB.GameFunction | TB.GameFunction[] | number | number[]): string[] {
    let func: TB.GameFunction[];
    if (Array.isArray(redDotName)) {
      if (redDotName.length <= 0) return;
      if (redDotName[0] instanceof TB.GameFunction) {
        func = redDotName as TB.GameFunction[];
      } else {
        const tb = DataMgr.tables.TbGameFunction;
        func = [];
        (redDotName as number[]).forEach((ele: number) => {
          func.push(tb.get(ele));
        });
      }
    } else {
      if (typeof redDotName === 'number') {
        const tb = DataMgr.tables.TbGameFunction;
        func = [tb.get(redDotName)];
      } else {
        func = [redDotName as TB.GameFunction];
      }
    }
    const rName = this.addRedDotConfig(func);
    const result = [];
    rName.forEach((nn) => {
      result.push(...this.redDotTrie.getWordAboutList(nn));
    });
    // RedDotManager.Instantiate().triggerRedDotNameUpdate(result);
    return result;
  }
}
